// 多态
// Created by FanGccU on 2025/6/14.
//
#include <iostream>
using namespace std;


/**
 * 多态发生在类之间存在层次关系并且是继承状态。
 * virtual：表示函数是虚函数可以有默认实现但是派生可以进行重写
 *
 */
class Animal {
public:
    // virtual 表示该函数是虚函数，子类可以重写（非必须），虚函数被存储在虚函数表中
    virtual void sound() {
        cout << "Animal sound" << endl;
    }

    // 虚析函数：确保派生类对象在通过基类指针删除时，能正确调用派生类的析构函数，避免内存泄露
    // 如果通过基类指针删除派生类对象，而基类没有虚析构函数，那么只会调用基类的析构函数，不会调用派生类的析构函数
    virtual ~Animal() {
        cout << "Animal destroyed" << endl;
    }

private:
    // 私有访问修饰符的虚函数也可以被重写
    virtual void walk() {
        cout << "Animal walk" << endl;
    }
};

class Dog : public Animal {
public:
    // 重写基类的 sound 函数
    void sound() override {
        cout << "Dog sound" << endl;
    }

    // 重写基类私有的虚函数
    void walk() override {
        cout << "Dog walk" << endl;
    }

    ~Dog() {
        cout << "Dog destroyed" << endl;
    }
};

class Cat : public Animal {
public:
    // 重写基类的 sound 函数
    void sound() override {
        cout << "Cat sound" << endl;
    }

    void walk() override {
        cout << "Cat walk" << endl;
    }

    // 析构函数（基类必须要有虚析构函数否则派生类的析构函数不会调用）
    ~Cat() {
        cout << "Cat Destroyed" << endl;
    }
};

int main(int argc, char *argv[]) {
    // 创建基类指针
    Animal *animal;

    // 基类指针指向派生来 Dog
    animal = new Dog();
    animal->sound();

    // 释放内存，调用 Dog 和 Animal 的析构函数
    delete animal;

    animal = new Cat();
    animal->sound();

    delete animal;

    Dog dog;
    dog.walk();
}


/**
 * 纯虚函数
 * 纯虚函数是抽象函数，抽象函数在基类中没有实现，只能声明，不能定义。
 * 抽象函数必须由派生类实现
 * 有抽象函数的类是抽象类，抽象类不能创建对象
 */

class Shape {
protected:
    int width;
    int height;

public:
    // = 0 表示是抽象函数，不能有方法体，必须有派生类实现
    virtual int area() = 0;

    // 构造函数
    Shape(int w, int h): width(w), height(h) { ; }
};

class Rectangle : public Shape {
public:
    // 构造函数，调用基类的构造函数
    Rectangle(int w, int h): Shape(w, h) { ; }
    // 实现基类的函数
    int area() override {
        return width * height;
    }
};

// int main(int argc, char *argv[]) {
//     // Shape shape; // 有抽象函数的类是抽象类，抽象类不能实例化
//     Shape *shap = new Rectangle(10, 20);
//     cout << "Rectangle area is: " << shap->area() << endl;
//     delete shap;
// }
